package com.atguigu.filer;


import com.alibaba.fastjson.JSONObject;
import com.atguigu.result.RetVal;
import com.atguigu.result.RetValCodeEnum;
import com.atguigu.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * AccessFilter
 *
 * @author yangchao
 * @version 开发阶段
 * @description TODO
 * @date 2022/3/3 13:41
 */
@Component
public class AccessFilter implements GlobalFilter {
    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${filter.whiteList}")
    private String filterWhiteList;


    // 创建匹配对象
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        //1.若果sku 开头 无权限访问  http://item.gmall.com/sku/getSkuInfo/41
        if (antPathMatcher.match("/sku/**", path)) {
            ServerHttpResponse response = exchange.getResponse();
            return writeDataToBrowser(response, RetValCodeEnum.NO_PERMISSION);  //没有权限
        }
        //2.用户信息核实 ip地址+cookie
        //获取用户的id信息
        String userId = getLoginUserId(request);
        String userTempId = getUserTempId(request);
        //cookie被盗 提示没有权限
        if ("-1".equals(userId)) {
            ServerHttpResponse response = exchange.getResponse();
            return writeDataToBrowser(response, RetValCodeEnum.NO_PERMISSION);
        }

        //如果要看订单相关信息是需要进行登录的
        if (antPathMatcher.match("/order/**", path)) {
            //如果是未登录情况
            if (StringUtils.isEmpty(userId)) {
                ServerHttpResponse response = exchange.getResponse();
                return writeDataToBrowser(response, RetValCodeEnum.NO_LOGIN);
            }
        }
        //访问拦截路径名单 对于这些请求路径需要进行拦截,跳转到登录页面
        for (String filterWhite : filterWhiteList.split(",")) {
            //用户访问的url中包含上述数据，并且用户未登录
            if (path.indexOf(filterWhite) != -1 && StringUtils.isEmpty(userId)) {
                //设置完成之后重定向
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION, "http://passport.gmall.com/login.html?originalUrl=" + request.getURI());
                return response.setComplete();
            }
        }
        //5.把用户id需要保存到header中 传给shop-web那边的request
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)) {
            if (!StringUtils.isEmpty(userId)) {
                //将用户id放入header当中
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)) {
                request.mutate().header("userTempId", userTempId).build();
            }
            //过滤器放开拦截器 让下游请求继续执行(此时修改了exchange对像)
            return chain.filter(exchange.mutate().request(request).build());
        }
        return chain.filter(exchange);
    }

    private String getUserTempId(ServerHttpRequest request) {
        // 获取header中的数据
        String userTempId = "";
        List<String> result = request.getHeaders().get("userTempId");
        // 判断集合不为空！
        if (!CollectionUtils.isEmpty(result)) {
            userTempId = result.get(0);
        } else {
            // 表示在header 中没有获取到数据，从cookie中获取
            HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
            if (httpCookie != null) {
                userTempId = httpCookie.getValue();
            }
        }
        return userTempId;
    }


    //把数据写到浏览器中方法
    private Mono<Void> writeDataToBrowser(ServerHttpResponse response, RetValCodeEnum retValCodeEnum) {
        RetVal<Object> retVal = RetVal.build(null, retValCodeEnum);
        //把对象转换为字节
        byte[] bytes = JSONObject.toJSONString(retVal).getBytes(StandardCharsets.UTF_8);
        //将字节数组变为一个数据buffer
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
        //设置页面的头部信息为返回json数据编码为utf-8
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(dataBuffer));
    }

    //获取登录用户Id
    private String getLoginUserId(ServerHttpRequest request) {
        /**
         * 获取登录用户id信息(反着写代码)
         * 1.用户id信息存储在redis中
         * 2.那么就得先拼接redis的key---> String userKey = RedisConst.USER_LOGIN_KEY_PREFIX+token;
         * 3.如何拿到token 从cookie(pc端) header(移动端)
         */
        String token = "";
        //header一般存储在移动端
        List<String> result = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(result)) {
            token = result.get(0);
        } else {
            //如果header中没有获取到token 那么从cookie里面去获取
            HttpCookie cookie = request.getCookies().getFirst("token");
            if (cookie != null) {
                token = cookie.getValue();
            }
        }
        if (!StringUtils.isEmpty(token)) {
            //根据token获取用户登录信息
            String userKey = "user:login:" + token;
            String loginInfoJson = (String) redisTemplate.opsForValue().get(userKey);
            // redis 没有 用户登录信息 或者过期
            if (StringUtils.isEmpty(loginInfoJson)) {
                return "-1";
            }
            JSONObject loginInfo = JSONObject.parseObject(loginInfoJson);
            String loginIp = loginInfo.getString("loginIp");
            //获取到登录时ip
            String currentIpAddress = IpUtil.getGatwayIpAddress(request);
            //判断当前电脑登录ip是否与存储ip一致 如果一致取得userId,如果不一致返回"-1"
            if (loginIp.equals(currentIpAddress)) {
                //防止cookie被盗用所以做了一步判断
                return loginInfo.getString("userId");
            } else {
                return "-1";
            }
        }
        return null;
    }


}